﻿using Minecraft.Config;
using Minecraft.Config.Csv.CsvCls;
using Minecraft.Model;
using Minecraft.Model.Map;
using Minecraft.Model.Mod;
using Minecraft.Model.ReqResp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Minecraft.ServerHall
{
	public static class MapExt
	{
		public static List<string> GetUnlockedDepotIdList(this MapModel map)
		{
			List<string> li = map.UnlockedDepotIds.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToList();
			if (li == null || !li.Any())
			{
				li = new List<string>();
				li.Add(MinecraftConfig.BaseMapId);
			}
			return li;
		}
		public static void TransformToUnlockedDepotIdsStr(this MapModel map, string depotId)
		{
			var list = map.GetUnlockedDepotIdList();
			list.Add(depotId);
			list = list.Distinct().ToList();
			map.UnlockedDepotIds = string.Join("|", list.ToArray());
		}
		/// <summary>
		/// 获取所需的体力值
		/// </summary>
		/// <param name="sourcePoint3"></param>
		/// <param name="distPoint3"></param>
		/// <returns></returns>
		public static int GetNeedPhysicalStrengthValue(this Point3 sourcePoint3, Point3 distPoint3)
		{
			var dist = sourcePoint3.GetDist(distPoint3);
			var totalSecond = dist / MinecraftConfig.MapTranslationalSpeed_low;
			return Convert.ToInt32(totalSecond * MinecraftConfig.PhysicalStrengthValueQuotiety);
		}
		/// <summary>
		/// 获得三维坐标两点之间的距离
		/// </summary>
		/// <param name="sourcePoint3"></param>
		/// <param name="distPoint3"></param>
		/// <returns></returns>
		public static double GetDist(this Point3 sourcePoint3, Point3 distPoint3)
		{
			return Math.Sqrt(Math.Pow(sourcePoint3.x - distPoint3.x, 2) + Math.Pow(sourcePoint3.y - distPoint3.y, 2) + Math.Pow(sourcePoint3.z - distPoint3.z, 2));
		}
		/// <summary>
		/// 获取map的时间ticks集合
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		public static Dictionary<int, DateTime> GetTimeTicksDict(this MapModel map)
		{
			Dictionary<int, DateTime> dict = new Dictionary<int, DateTime>();
			var strs = map.TimeTicks.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (var str in strs)
			{
				var ts = str.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
				dict.Add(Convert.ToInt32(ts[0]), new DateTime(long.Parse(ts[1])));
			}
			return dict;
		}
		/// <summary>
		/// 获取所有可视范围内的地图Id列表（包括基地，补给站，小地图）
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		public static List<string> GetWithinVisualRangeMapIdList(this MapModel map)
		{
			//先获取已经解锁的最大layerBig值
			var mapTransLi = CsvConfig.modMapTransformInfoList.Where(m => map.GetUnlockedDepotIdList().Any(k => k == m.mapId)).ToList();
			var unlockedLayerBig = mapTransLi.Max(m => m.layerBig);
			//再得到 layerBig 为 unlockedLayerBig+1 的小地图列表
			var canVisualLayerBig = unlockedLayerBig + 1;
			var canVisualLi = CsvConfig.modMapTransformInfoList.Where(m => m.layerBig <= canVisualLayerBig).ToList();
			var mapIdLi = canVisualLi.Select(m => m.mapId).ToList();
			return mapIdLi;
		}

		/// <summary>
		/// 判断mapid是否在可视范围内
		/// </summary>
		/// <param name="map"></param>
		/// <param name="mapId"></param>
		/// <returns></returns>
		public static bool IsWithinVisualField(this MapModel map, string mapId)
		{
			return map.GetWithinVisualRangeMapIdList().Any(m => m == mapId);
		}

		/// <summary>
		/// 得到最佳路径（地图移动）
		/// </summary>
		/// <param name="sourceMap"></param>
		/// <param name="targetMap"></param>
		/// <returns></returns>
		public static List<string> GetRouteIdList(this MapModel map, Mod_Map sourceMap, Mod_Map targetMap, bool isAccelerating)
		{
			List<List<string>> resultRouteList = new List<List<string>>(); //所有路线的存储

			var sourceModMapTransformInfo = CsvConfig.modMapTransformInfoList.FirstOrDefault(m => m.mapId == sourceMap.Id);
			var targetModMapTransformInfo = CsvConfig.modMapTransformInfoList.FirstOrDefault(m => m.mapId == targetMap.Id);
			var sourceLayerBig = sourceModMapTransformInfo.layerBig;
			var targetLayerBig = targetModMapTransformInfo.layerBig;
			if (sourceLayerBig == targetLayerBig)
			{
				List<string> mapIdList = new List<string>();
				var sourceLayerSamll = sourceModMapTransformInfo.layerSmall;
				var targetLayerSmall = targetModMapTransformInfo.layerSmall;
				if (sourceLayerSamll == targetLayerSmall)
				{
					mapIdList.Add(sourceMap.Id);
					mapIdList.Add(targetMap.Id);
				}
				else
				{
					//在同一大层级，但不在同一小层级
					mapIdList.Add(sourceMap.Id);
					if (!targetMap.If_depot_Convert) //如果目标地图不是补给站，还要加上目标地图所属的补给站
					{
						var targetDeoptInfo = CsvConfig.modMapTransformInfoList.FirstOrDefault(m => m.If_depot && m.layerBig == targetModMapTransformInfo.layerBig && m.layerSmall == targetModMapTransformInfo.layerSmall);
						mapIdList.Add(targetDeoptInfo.mapId);
						mapIdList.Add(targetMap.Id);
					}
					else
					{
						mapIdList.Add(targetMap.Id);
					}
				}
				resultRouteList.Add(mapIdList);
			}
			else
			{
				//不在同一大层级，要计算最佳路线
				var betweenDepotInfoList = (from info in CsvConfig.modMapTransformInfoList
											where info.If_depot && info.mapId != MinecraftConfig.BaseMapId
												&& (info.layerBig > sourceLayerBig && info.layerBig < targetLayerBig)
												|| (info.layerBig < sourceLayerBig && info.layerBig > targetLayerBig)
											group info by new { info.layerBig } into g
											orderby g.Key.layerBig
											select
											(from gItem in g
											 select gItem.mapId).ToList()
													).ToList();

				List<List<string>> routeList = new List<List<string>>();
				List<string> singleList = new List<string>(); //单个路线的存储
				if (betweenDepotInfoList != null && betweenDepotInfoList.Any())
				{
					betweenDepotInfoList.CartesianProduct(ref routeList);
				}
				if (routeList != null && routeList.Any())
				{
					foreach (var route in routeList)
					{
						singleList = new List<string>();
						singleList.Add(sourceMap.Id);
						singleList.AddRange(route);
						if (!targetMap.If_depot_Convert)//如果目标地图不是补给站
						{
							var targetDeoptInfo = CsvConfig.modMapTransformInfoList.FirstOrDefault(m => m.If_depot && m.layerBig == targetModMapTransformInfo.layerBig && m.layerSmall == targetModMapTransformInfo.layerSmall);
							singleList.Add(targetDeoptInfo.mapId);
							singleList.Add(targetMap.Id);
							//加上直达的情况
							resultRouteList.Add(new List<string> { sourceMap.Id, targetMap.Id });
						}
						else//如果目标地图是补给站
						{
							singleList.Add(targetMap.Id);
						}
						resultRouteList.Add(singleList);
					}
				}
				else
				{
					singleList = new List<string>();
					singleList.Add(sourceMap.Id);
					if (!targetMap.If_depot_Convert)//如果目标地图不是补给站
					{
						var targetDeoptInfo = CsvConfig.modMapTransformInfoList.FirstOrDefault(m => m.If_depot && m.layerBig == targetModMapTransformInfo.layerBig && m.layerSmall == targetModMapTransformInfo.layerSmall);
						singleList.Add(targetDeoptInfo.mapId);
						singleList.Add(targetMap.Id);
						//加上直达的情况
						resultRouteList.Add(new List<string> { sourceMap.Id, targetMap.Id });
					}
					else//如果目标地图是补给站
					{
						singleList.Add(targetMap.Id);
					}
					resultRouteList.Add(singleList);
				}
			}
			//得到最佳路线
			var bestRoute = map.GetBestRoute(resultRouteList, isAccelerating);
			return bestRoute;
		}
		/// <summary>
		/// 得到最佳路线
		/// </summary>
		/// <param name="resultRouteList"></param>
		/// <returns></returns>
		private static List<string> GetBestRoute(this MapModel map, List<List<string>> resultRouteList, bool isAccelerating)
		{
			//顺便算出距离，总时间，剩余时间
			List<string> route = new List<string>();
			if (resultRouteList == null || !resultRouteList.Any())
			{
				throw new Exception("路线为空");
			}
			else
			{
				if (resultRouteList.Count() == 1)
				{
					route = resultRouteList.FirstOrDefault();
				}
				else
				{
					//有多个路线的情况，是否已经解锁
					if (!isAccelerating)
					{
						//距离列表
						Dictionary<int, double> distDict = new Dictionary<int, double>();
						for (int k = 0; k < resultRouteList.Count(); k++)
						{
							var resultRoute = resultRouteList[k];
							double dist = map.GetDist(resultRoute);
							distDict.Add(k, dist);
						}
						//非加速状态下算距离最短的路线
						var key = distDict.FirstOrDefault(m => m.Value == distDict.Values.Min()).Key;
						route = resultRouteList[key];
					}
					else
					{
						//加速状态下，算所消耗的体力值最少的路线
						Dictionary<int, int> physicalStrengthDict = new Dictionary<int, int>();
						for (int k = 0; k < resultRouteList.Count(); k++)
						{
							var resultRoute = resultRouteList[k];
							int physicalStrengthValue = map.GetPhysicalStrengthByRoute(resultRoute);
							physicalStrengthDict.Add(k, physicalStrengthValue);
						}
						var key = physicalStrengthDict.FirstOrDefault(m => m.Value == physicalStrengthDict.Values.Min()).Key;
						route = resultRouteList[key];
					}
				}
			}
			return route;
		}

		/// <summary>
		/// 算指定路线的总距离
		/// </summary>
		/// <param name="route"></param>
		/// <returns></returns>
		public static double GetDist(this MapModel map, List<string> route)
		{
			double dist = 0;
			for (int i = 0; i < route.Count() - 1; i++)
			{
				//var modMap1 = CsvConfig.mapList.FirstOrDefault(m => m.Id == route[i]);
				//var modMap2 = CsvConfig.mapList.FirstOrDefault(m => m.Id == route[i + 1]);
				var modMap1 = CsvConfig.GetMod_MapInfoById(route[i]);
				var modMap2 = CsvConfig.GetMod_MapInfoById(route[i + 1]);
				dist += modMap1.point3.GetDist(modMap2.point3);
			}
			return Math.Round(dist, 2);
		}
		/// <summary>
		/// 获取指定路线的体力值
		/// </summary>
		/// <param name="map"></param>
		/// <param name="route"></param>
		/// <returns></returns>
		public static int GetPhysicalStrengthByRoute(this MapModel map, List<string> route)
		{
			if (route == null && route.Count() < 2)
			{
				throw new Exception("路线 route == null && route.Count() < 2");
			}
			int physicalStrengthValue = 0;
			for (int i = 0; i < route.Count() - 1; i++)
			{
				//var modMap1 = CsvConfig.mapList.FirstOrDefault(m => m.Id == route[i]);
				//var modMap2 = CsvConfig.mapList.FirstOrDefault(m => m.Id == route[i + 1]);
				var modMap1 = CsvConfig.GetMod_MapInfoById(route[i]);
				var modMap2 = CsvConfig.GetMod_MapInfoById(route[i + 1]);
				var unlockedDepotIdList = map.GetUnlockedDepotIdList();
				unlockedDepotIdList.Remove(MinecraftConfig.BaseMapId);
				if (!unlockedDepotIdList.Any(m => m == modMap2.Id))
				{
					physicalStrengthValue += GetNeedPhysicalStrengthValue(modMap1.point3, modMap2.point3);
				}
			}
			return physicalStrengthValue;
		}

		public static BaseResp GetMapNewRespInfo(this MapModel map, MinecraftSession session, out MapNewRespInfo mapRespInfo)
		{
			mapRespInfo = null;
			session.SetCurPhysicalStrengthValue();

			//var sourceMap = CsvConfig.mapList.FirstOrDefault(m => m.Id == map.SourceMapId);
			var sourceMap = CsvConfig.GetMod_MapInfoById(map.SourceMapId);
			if (sourceMap == null)
			{
				return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误4：（原因：原地图信息不存在）" };
			}

			var timeNow = DateTimeOffset.Now;

			Dictionary<int, DateTime> dict = map.GetTimeTicksDict();

			//if (JsonConfig.Value.IsDebug)
			//{
			//	dict.Clear();
			//	dict.Add(0, timeNow.AddSeconds(-1));
			//	map.targetMapId = "600010";
			//}

			var isMoving = false;
			var isAccelerating = false;
			int totalSecond = 0;
			int remainSecond = 0;
			//路线
			List<string> mapRoute = new List<string>() { sourceMap.Id };

			switch (dict.Count())
			{
				case 0:
					{
						//if (map.isBig_Convert)
						//{
						if (!map.isMoving_Convert)
						{
							//静止
							isMoving = false;
						}
						else
						{
							return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误3：（原因：数据出错）" };
						}
						//}
						//else
						//{
						//	//处在小地图中（暂放）
						//}
					}
					break;
				case 1:
					{
						var first = dict.FirstOrDefault();
						if (first.Key == 0)
						{
							isMoving = true;
							//不加速中
							isAccelerating = false;
							//算时间
							//var targetMap = CsvConfig.mapList.FirstOrDefault(m => m.Id == map.TargetMapId);
							var targetMap = CsvConfig.GetMod_MapInfoById(map.TargetMapId);
							if (targetMap == null)
							{
								return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误4：（原因：目标地图信息不存在）" };
							}
							mapRoute = map.GetRouteIdList(sourceMap, targetMap, isAccelerating);
							//var dist = sourceMap.point3.GetDist(targetMap.point3);
							var dist = map.GetDist(mapRoute);
							totalSecond = Convert.ToInt32(dist / MinecraftConfig.MapTranslationalSpeed_low);

							remainSecond = Convert.ToInt32(totalSecond - (timeNow - first.Value).TotalSeconds);

							if (remainSecond <= 0)
							{
								//已经到达
								isMoving = false;
								isAccelerating = false;
								totalSecond = 0;
								remainSecond = 0;
								map.LastMapId = map.SourceMapId;
								map.SourceMapId = targetMap.Id;
								map.TargetMapId = "";
								map.TimeTicks = "";
								mapRoute = new List<string>() { targetMap.Id };

								//切换场景
								session.SwitchingScene(map);
							}
						}
						else if (first.Key == 1)
						{
							isMoving = true;
							//加速中
							isAccelerating = true;
							//算时间
							//var targetMap = CsvConfig.mapList.FirstOrDefault(m => m.Id == map.TargetMapId);
							var targetMap = CsvConfig.GetMod_MapInfoById(map.TargetMapId);
							if (targetMap == null)
							{
								return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误4：（原因：目标地图信息不存在）" };
							}
							mapRoute = map.GetRouteIdList(sourceMap, targetMap, isAccelerating);
							//var dist = sourceMap.point3.GetDist(targetMap.point3);
							var dist = map.GetDist(mapRoute);
							totalSecond = Convert.ToInt32(dist / MinecraftConfig.MapTranslationalSpeed_fast);
							remainSecond = Convert.ToInt32(totalSecond - (timeNow - first.Value).TotalSeconds);
							if (remainSecond <= 0)
							{
								//已经到达
								isMoving = false;
								isAccelerating = false;
								totalSecond = 0;
								remainSecond = 0;
								map.LastMapId = map.SourceMapId;
								map.SourceMapId = targetMap.Id;
								map.TargetMapId = "";
								map.TimeTicks = "";
								mapRoute = new List<string>() { targetMap.Id };

								//切换场景
								session.SwitchingScene(map);
							}
						}
						else
						{
							return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误6：（原因：数据出错）" };
						}
					}
					break;
				default:
					{
						return new BaseResp { RespLevel = RespLevelEnum.Error, Msg = "错误10：（原因：dict.Count() > 2）" };
					}
			}

			mapRespInfo = new MapNewRespInfo
			{
				mapIdList = mapRoute,
				//sourceMapId = map.sourceMapId,
				//targetMapId = map.targetMapId,
				isMoving = isMoving,
				isAccelerating = isAccelerating,
				totalSecond = totalSecond,
				remainSecond = remainSecond,
				curPhysicalStrengthValue = session.minecraftSessionInfo.player.PhysicalStrengthValue,
				PhysicalStrengthValueDistanceSeconds = Convert.ToInt32((timeNow - session.minecraftSessionInfo.player.PhysicalStrengthLastGrowTime).TotalSeconds),
				unlockedDepotIdList = map.GetUnlockedDepotIdList(),// new List<string>() { MinecraftConfig.BaseMapId, "600005" },
			};
			return new BaseResp() { RespLevel = RespLevelEnum.Success, Msg = "" };
		}
		/// <summary>
		/// 进入基地的处理（记录时间）
		/// </summary>
		/// <param name="session"></param>
		/// <param name="mapId"></param>
		public static void IntoBase(this MinecraftSession session, string mapId)
		{
			if (mapId == MinecraftConfig.BaseMapId)
			{
				session.minecraftSessionInfo.player.LastIntoBaseTime = session.minecraftSessionInfo.player.RecentlyIntoBaseTime;
				session.minecraftSessionInfo.player.RecentlyIntoBaseTime = DateTimeOffset.Now;
			}
		}
	}
}
